package com.andnnl.allocator;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 按比例分配
 * Created by chenss on 2023/12/13.
 */
public class ProportionAllocatorTest {
    private Map<String, AtomicInteger> countMap = new ConcurrentHashMap<>();
    private String[] tags;
    private int[] proportions;

    public ProportionAllocatorTest(String[] tags, int[] proportions) {
        this.tags = tags;
        this.proportions = proportions;
    }


    /**
     * 算法：获取总体的比例，把当前比例最小的那个+1
     * 设置比例为0时，排除分配
     * 加 synchronized，返回每次的结果都比较均匀，不加的话，多线程环境下每次都不一样，但总统计量变化不大（高并发环境下除外）
     *
     * @param numbers
     * @return
     */
    public synchronized Map<String, AtomicInteger> allocate2(List<Integer> numbers) {
        int calCount = 0;//当前计数器
        Map<String, AtomicInteger> resultMap = new HashMap<>();
        while (calCount < numbers.size()) {
            int minIdx = 0;
            double minRatio = Double.MAX_VALUE;
            for (int i = 0; i < tags.length; i++) {
                if (proportions[i] <= 0) continue;//跳过比例为0的
                String element = tags[i];
                AtomicInteger atomicInteger = countMap.computeIfAbsent(element, k -> new AtomicInteger(0));
                double curRatio = (double) (atomicInteger.get()) / proportions[i];//计算当前计数占用比例
                //取最低比例的+1
                if (curRatio < minRatio) {
                    minRatio = curRatio;
                    minIdx = i;
                }
            }
            calCount++;
            String element = tags[minIdx];
            countMap.computeIfAbsent(element, k -> new AtomicInteger(0)).incrementAndGet();
            resultMap.computeIfAbsent(element, k -> new AtomicInteger(0)).incrementAndGet();
            System.out.println("minIdx->" + minIdx + " " + minRatio);
            System.out.println("+++++++++++++++++++++++");
        }
        return resultMap;
    }

    public static void main(String[] args) throws InterruptedException {
        Map<String, AtomicInteger> countResultMap = new ConcurrentHashMap<>();

//        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> numbers = Arrays.asList(1);
        String[] tags = {"a", "b", "c"};
        int[] proportions = {0, 1, 3};
        ProportionAllocatorTest allocator = new ProportionAllocatorTest(tags, proportions);
        ExecutorService exec = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 150; i++) {
            exec.submit(() -> {
                Map<String, AtomicInteger> resultMap = allocator.allocate2(numbers);
                resultMap.entrySet().forEach(e -> {
                    countResultMap.computeIfAbsent(e.getKey(), k -> new AtomicInteger(0)).addAndGet(e.getValue().get());
                });
                System.out.println(resultMap);
                System.out.println("   " + countResultMap);

                System.out.println();
            });
        }

        Thread.sleep(100);
        System.out.println("countMap:" + allocator.countMap);
    }
}
